package tq.com.tqstudent.net;

import android.annotation.SuppressLint;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import com.lib.common.utils.LogUtil;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.net.URLEncoder;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class SCHttpClient {
    static final private SCHttpClient shareClient = new SCHttpClient();
    private static String httpUrl;
    static private String TAG = "SCHttpClient";
    private Handler mainHandler = new Handler(Looper.getMainLooper());
    private OkHttpClient mOkHttpClient;

    static public String BASE_URL = "http://www.banqun123.com:5262";
    static public String fullUrl(String f){
        return String.format("%s%s", BASE_URL, f);
    }

    static public String BASE_PIC_URL = "http://v1.shipin3600.com";
    static public String picUrl(String f){
        int index = f.indexOf(BASE_PIC_URL);
        if(index != -1){
            String wrong = String.format("%s//", BASE_PIC_URL);
            index = f.indexOf('\n');
            if(index != -1){
                String suf = f.substring(index + 1);
                return String.format("%s/%s", BASE_PIC_URL, suf);
            }else{
                return f;
            }
        }else if(f.length() > "http".length()){
            String sch = f.substring(0, "http".length());
            if(sch.equalsIgnoreCase("http")){
                return f;
            }
        }

        if(f.startsWith("/")){
            return String.format("%s%s", BASE_PIC_URL, f);
        }else {
            return String.format("%s/%s", BASE_PIC_URL, f);
        }
    }

    static public SCHttpClient httpClient(){
        return shareClient;
    }
    public void get(String url, Map<String, String> param, SCHttpCallback pCallback){
        if(url == null || url.length() == 0){
            if(pCallback != null){
                pCallback.result(SCHttpResult.RET_PARAM_ERROR);
            }
            return;
        }

        httpUrl = url;
        Request.Builder requestBuild = getBuild(url, param, false);
        Request request = requestBuild.build();
        getOkHttpClient().newCall(request).enqueue(new NetCallback(pCallback, request.url().toString()));
    }

    public void postWithUrlEncode(String url, Map<String, String> param, SCHttpCallback pCallback){
        if(url == null || url.length() == 0){
            if(pCallback != null){
                pCallback.result(SCHttpResult.RET_PARAM_ERROR);
            }
            return;
        }

        httpUrl = url;
        Request.Builder requestBuild = getBuild(url, param, true);
        Request request = requestBuild.build();
        getOkHttpClient().newCall(request).enqueue(new NetCallback(pCallback, request.url().toString()));
    }

    public void postJson(String url, String jsonParam, SCHttpCallback pCallback){
        if(!isTrueUrl(url, pCallback)){
            return;
        }

        httpUrl = url;
        Request.Builder requestBuild = getBuild(url, jsonParam, true);
        Request request = requestBuild.build();
        getOkHttpClient().newCall(request).enqueue(new NetCallback(pCallback, request.url().toString()));
    }

    private boolean isTrueUrl(String url, SCHttpCallback pCallback){
        if(url == null || url.length() == 0){
            if(pCallback != null){
                pCallback.result(SCHttpResult.RET_PARAM_ERROR);
            }
            return false;
        }

        return true;
    }

    //multi form
    public void postMultiForm(String url, MultipartBody pBody, SCHttpCallback pCallback){
        if(url == null || url.length() == 0){
            if(pCallback != null){
                pCallback.result(SCHttpResult.RET_PARAM_ERROR);
            }
            return;
        }

        httpUrl = url;

        Request.Builder lBuilder = new Request.Builder()
                .url(url)
                .post(pBody);
        Request request = lBuilder.build();
        getOkHttpClient().newCall(request).enqueue(new NetCallback(pCallback, request.url().toString()));

    }
    //为神奇的一个接口专门准备
    public void postWithSameKeyForm(String url, String key, ArrayList<String>value, SCHttpCallback pCallback){
        if(url == null || url.length() == 0){
            if(pCallback != null){
                pCallback.result(SCHttpResult.RET_PARAM_ERROR);
            }
            return;
        }

        httpUrl = url;

        FormBody.Builder lBuilder1 = new FormBody.Builder();
        for (String v:
             value) {
            lBuilder1.add(key, v);
        }

        Request.Builder lBuilder = new Request.Builder()
                .url(url)
                .post(lBuilder1.build());
        Request request = lBuilder.build();
        getOkHttpClient().newCall(request).enqueue(new NetCallback(pCallback, request.url().toString()));
    }

    public void postWithForm(String url, Map<String, String> param, SCHttpCallback pCallback){
        if(url == null || url.length() == 0){
            if(pCallback != null){
                pCallback.result(SCHttpResult.RET_PARAM_ERROR);
            }
            return;
        }

        httpUrl = url;

        FormBody.Builder lBuilder1 = new FormBody.Builder();
        for (Map.Entry<String, String> e:
             param.entrySet()) {
            lBuilder1.add(e.getKey(), e.getValue());
        }

        Request.Builder lBuilder = new Request.Builder()
                .url(url)
                .post(lBuilder1.build());
        Request request = lBuilder.build();
        getOkHttpClient().newCall(request).enqueue(new NetCallback(pCallback, request.url().toString()));
    }

    //get
    private Request.Builder getBuild(String str, Map<String, String> param, boolean post){
        String fullUrl = str;
        if(param != null && param.size() > 0){
            fullUrl = makeUrlEncodeParam(param, str);
        }
        Request.Builder lBuilder = new Request.Builder().url(fullUrl);
        if(post){
            lBuilder.get().post(RequestBody.create(null, ""));
        }else{
            lBuilder.get();
        }

//        if(SCLogin.shareInstance().hasToken()){
////            lBuilder.addHeader("xxx_api_auth", SCLogin.shareInstance().getToken());
//        }
        return lBuilder;
    }

    private Request.Builder getBuild(String str, String jsonParam, boolean post){
        String fullUrl = str+jsonParam;
        Request.Builder lBuilder = new Request.Builder().url(fullUrl);
        if(post){
            lBuilder.get().post(RequestBody.create(null, ""));
        }else{
            lBuilder.get();
        }

//        if(SCLogin.shareInstance().hasToken()){
////            lBuilder.addHeader("xxx_api_auth", SCLogin.shareInstance().getToken());
//        }
        return lBuilder;
    }

    private String makeUrlEncodeParam(Map<String, String> param, String url){

        StringBuffer mulString = new StringBuffer(url);
        for (Map.Entry<String, String> entry : param.entrySet()) {
            int pos = mulString.indexOf("?");

            String v = entry.getValue();
            try{
                v = URLEncoder.encode(v, "UTF-8");
            }catch (Exception e){
                continue;
            }

            if(pos == -1){
                mulString.append(String.format("?%s=%s", entry.getKey(), v));
            }else{
                mulString.append(String.format("&%s=%s", entry.getKey(), v));
            }
        }



        return mulString.toString();
    }
    private OkHttpClient getOkHttpClient(){
        if(mOkHttpClient == null){
            mOkHttpClient = new OkHttpClient.Builder()
                    .connectTimeout(5, TimeUnit.SECONDS)
                    .readTimeout(10, TimeUnit.SECONDS)
                    .sslSocketFactory(createSSLSocketFactory())
                    .hostnameVerifier(new TrustAllHostnameVerifier())
                    .cookieJar(new CookieJar() {
                        @Override
                        public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
                            Log.d(TAG, "saveFromResponse: ");
                        }

                        @Override
                        public List<Cookie> loadForRequest(HttpUrl url) {
                            ArrayList<Cookie> lCookies = new ArrayList<>();
//                            if(SCLogin.shareInstance().hasToken()){
//                                Cookie lCookie = new Cookie.Builder()
//                                        .hostOnlyDomain(url.host())
//                                        .name("xxx_api_auth").value(SCLogin.shareInstance().getToken())
//                                        .build();
//
//                                lCookies.add(lCookie);
//
//                                Cookie lCookie1 = new Cookie.Builder().hostOnlyDomain(url.host())
//                                        .name("path").value("/").build();
//
//                                lCookies.add(lCookie1);
//                            }
                            return lCookies;
                        }
                    })
            .build();
        }

        return mOkHttpClient;
    }

    class NetCallback implements Callback{
        private SCHttpCallback mSCHttpCallback;
        private String requestUrl;

        public NetCallback(SCHttpCallback pCallback, String requestUrl){
            mSCHttpCallback = pCallback;
            this.requestUrl = requestUrl;
        }

        public void onFailure(Call call, IOException e){
            e.printStackTrace();
            if(mSCHttpCallback == null) return;
            dispatchMain(mSCHttpCallback, SCHttpResult.RET_NET_ERRROR);
        }

        public void onResponse(Call call, Response response) throws IOException{
            if(mSCHttpCallback == null)return;

            if(!response.isSuccessful() && response.code() != 500){
                dispatchMain(mSCHttpCallback, SCHttpResult.RET_NET_ERRROR);
                return;
            }

            String body = response.body().string();

            try {
                JSONObject lJSONObject = new JSONObject(body);
                SCHttpResult lSCHttpResult = SCHttpResult.fromJson(lJSONObject);
                dispatchMain(mSCHttpCallback, lSCHttpResult);

                LogUtil.e("requestUrl: "+requestUrl+" | result: "+body);
            }catch (JSONException e){
                e.printStackTrace();
                dispatchMain(mSCHttpCallback, SCHttpResult.RET_NET_ERRROR);
            }
        }
    }

    private void dispatchMain(SCHttpCallback pCallback, SCHttpResult ret){
        mainHandler.post(new Runnable() {
            @Override
            public void run() {
                pCallback.result(ret);
            }
        });
    }

    @SuppressLint("TrulyRandom")
    private static SSLSocketFactory createSSLSocketFactory() {

        SSLSocketFactory sSLSocketFactory = null;

        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, new TrustManager[]{new TrustAllManager()},
                    new SecureRandom());
            sSLSocketFactory = sc.getSocketFactory();
        } catch (Exception e) {
        }

        return sSLSocketFactory;
    }

    private static class TrustAllManager implements X509TrustManager {
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType)

                throws CertificateException {
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
    }

    private static class TrustAllHostnameVerifier implements HostnameVerifier {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    }
}
